package com.un.ebs.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.enums.PowerTypeEnum;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.product.domain.Product;
import com.un.ebs.product.mapper.ProductMapper;
import com.un.ebs.sys.domain.*;
import com.un.ebs.sys.dto.AppPowerAddDto;
import com.un.ebs.sys.dto.AppPowerUpdateDto;
import com.un.ebs.sys.dto.ObjectParentAndIndexChangeDto;
import com.un.ebs.sys.mapper.AppPowerMapper;
import com.un.ebs.sys.mapper.AppRolePowerAllExtMapper;
import com.un.ebs.sys.mapper.AppRolePowerDynamicMapper;
import com.un.ebs.sys.mapper.AppUserRoleMapper;
import com.un.ebs.sys.service.AppPowerService;
import com.un.ebs.sys.service.AppRoleService;
import com.un.ebs.sys.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2019-09-18
 */
@Service
public class AppPowerServiceImpl extends ServiceImpl<AppPowerMapper, AppPower> implements AppPowerService {

    @Autowired
    private AppUserRoleMapper appUserRoleMapper;

    @Autowired
    private AppRolePowerAllExtMapper powerAllExtMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private AppRolePowerDynamicMapper appRolePowerDynamicMapper;

    @Autowired
    private AppRoleService appRoleService;

    @Override
    public void add(AppPowerAddDto req) {
        AppPower obj = new AppPower();
        obj.setAppId(req.getAppId());
        obj.setCode(req.getCode());
        obj.setRouteType(req.getRouteType());
        obj.setIcon(req.getIcon());
        obj.setName(req.getName());
        obj.setIsShowSubMenu(req.isShowSubMenu());
        obj.setType(req.getType());
        obj.setUrl(req.getUrl());
        obj.setIsDelete(false);
        obj.setParentId(req.getParentId());
        if (StringUtils.isEmpty(req.getParentId())) {
            obj.setSort(getBaseMapper().maxSort());
        } else {
            obj.setSort(getBaseMapper().maxSortByParentId(req.getParentId()));
        }
        obj.insert();
    }

    @Override
    public void update(AppPowerUpdateDto req) {
        AppPower obj = getById(req.getId());
        obj.setAppId(req.getAppId());
        obj.setCode(req.getCode());
        obj.setRouteType(req.getRouteType());
        obj.setIcon(req.getIcon());
        obj.setName(req.getName());
        obj.setIsShowSubMenu(req.isShowSubMenu());
        obj.setType(req.getType());
        obj.setUrl(req.getUrl());
        obj.setParentId(req.getParentId());
        obj.updateById();
    }

    @Override
    public AppPower queryById(String id) {
        return getBaseMapper().selectById(id);
    }

    @Override
    public void changeParent(String id, String parentId) {
        AppPower obj = getById(id);
        obj.setParentId(parentId);
        getBaseMapper().updateById(obj);
    }

    @Transactional
    @Override
    public void changeParentOrIndexBatch(List<ObjectParentAndIndexChangeDto> list) {
        for (ObjectParentAndIndexChangeDto dto : list) {
            AppPower appPower = baseMapper.selectById(dto.getId());
            appPower.setParentId(dto.getParentId());
            appPower.setSort(dto.getIndex());
            appPower.updateById();
        }
    }

    @Override
    public List<AppPower> queryByParentId(String parentId) {
        QueryWrapper<AppPower> wrapper = Wrappers.query();
        wrapper.ge("parent_id", parentId);
        return getBaseMapper().selectList(wrapper);
    }

    @Override
    public IPage<AppPower> queryPageByParentId(String parentId, int pageSize, int pageIndex) {
        Page<AppPower> page = new Page<>(pageIndex, pageSize);
        QueryWrapper<AppPower> wrapper = Wrappers.query();
        wrapper.ge("parent_id", parentId);
        return getBaseMapper().selectPage(page, wrapper);
    }

    @Override
    public void delete(String id) {
        getBaseMapper().deleteById(id);
    }

    @Override
    public void changeSort(String id, int index) {
        AppPower obj = getById(id);
        obj.setSort(index);
        getBaseMapper().updateById(obj);
    }

    @Override
    public boolean checkPower(String id) {
        List<String> roleIds = userService.queryCurrRoles().stream().map(s -> s.getId()).collect(Collectors.toList());
        if (roleIds.size() <= 0) return false;

        LambdaQueryWrapper<AppRolePowerAllExt> query = Wrappers.lambdaQuery();
        query.eq(AppRolePowerAllExt::getAppId, SecurityUtils.getUserContent().getAppId());
        query.in(AppRolePowerAllExt::getRoleId, roleIds);
        query.eq(AppRolePowerAllExt::getId, id);
        List<AppRolePowerAllExt> powers = powerAllExtMapper.selectList(query);
        for (AppRolePowerAllExt p : powers) {
            if (p.getChecked()) return true;
        }
        return false;
    }

    private List<String> getRoles(String userId) {
        UserExt userExt = userService.getUserExt(userId);
        if (userExt == null) return new ArrayList<>();

        List<String> result = new ArrayList<>();
        LambdaQueryWrapper<AppUserRole> lq = Wrappers.lambdaQuery();
        lq.eq(AppUserRole::getUserId, userId);
        lq.eq(AppUserRole::getTenantId, userExt.getCurrentTenantId());
        List<AppUserRole> userRoleList = appUserRoleMapper.selectList(lq);
        if (userRoleList.size() <= 0) {
            return result;
        }

        result = userRoleList.stream().map(s -> s.getRoleId()).distinct().collect(Collectors.toList());
        return result;
    }

    private List<String> getRoles() {
        return getRoles(SecurityUtils.getUserContent().getId());
    }


    @Override
    public List<String> queryResourcePower(List<String> roleIds, PowerTypeEnum type) {
        LambdaQueryWrapper<AppRolePowerAllExt> query = Wrappers.lambdaQuery();
        query.eq(AppRolePowerAllExt::getAppId, SecurityUtils.getUserContent().getAppId());

        if (roleIds.size() > 0) {
            query.in(AppRolePowerAllExt::getRoleId, roleIds);
        } else {
            return new ArrayList<>();
        }
        query.eq(AppRolePowerAllExt::getType, type.getValue());
        List<AppRolePowerAllExt> list = powerAllExtMapper.selectList(query);

        List<String> ids = new ArrayList<>();
        if (list.size() > 0) {
            ids = list.stream().map(s -> s.getId()).collect(Collectors.toList());
        }
        if (ids.size() <= 0) {
            return new ArrayList<>();
        }

        if (type == PowerTypeEnum.Spu) {
            ids = checkInvalidResourceBySpu(ids);
        }
        return ids;
    }

    @Override
    public boolean checkResourcePower(String roleId, String resourceId, PowerTypeEnum type) {
//        List<String> roleIds = getRoles(userId);
        return queryResourcePower(roleId, type).contains(resourceId);
    }

    @Override
    public List<String> queryResourcePower(String roleId, PowerTypeEnum type) {
        List<String> ids = new ArrayList<>();
        ids.add(roleId);
        return queryResourcePower(ids, type);
    }

    @Override
    public List<String> queryResourcePower(PowerTypeEnum type) {
        return queryResourcePower(getRoles(), type);
    }

    @Override
    public List<UserExt> queryUserByResourcePower(String resourceId, PowerTypeEnum type) {
        LambdaQueryWrapper<AppRolePowerDynamic> lq = Wrappers.lambdaQuery();
        lq.eq(AppRolePowerDynamic::getResourceId, resourceId);
        lq.eq(AppRolePowerDynamic::getPowerType, type.getValue());
        List<String> roleIds = appRolePowerDynamicMapper.selectList(lq).stream().map(s -> s.getRoleId()).distinct().collect(Collectors.toList());
        return appRoleService.queryUserByRole(roleIds);

    }

    private List<String> checkInvalidResourceBySpu(List<String> ids) {
        LambdaQueryWrapper<Product> lq = Wrappers.lambdaQuery();
        lq.in(Product::getId, ids);
        lq.eq(Product::getIsDelete, false);
        return productMapper.selectList(lq).stream().map(s -> s.getId()).collect(Collectors.toList());
    }

}